#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <sys/time.h>
 
#include "data_type.h"
#include "cube.h"
#include "cube_define.h"
#include "cube_record.h"
#include "user_define.h"
#include "record_define.h"
#include "action_define.h"
#include "record_server.h"
// add para lib_include

const int id_size=16;

int record_server_init(void * sub_proc, void * para)
{
	int ret;
	// add yorself's module init func here
	return 0;
}
int record_server_start(void * sub_proc, void * para)
{
	int ret;
	void * recv_msg;
	int type;
	int subtype;
	// add yorself's module exec func here
	while(1)
	{
		usleep(time_val.tv_usec);
		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
		type=message_get_type(recv_msg);
		subtype=message_get_subtype(recv_msg);
		if(!memdb_find_recordtype(type,subtype))
		{
			printf("message format (%d %d) is not registered!\n",
			message_get_type(recv_msg),message_get_subtype(recv_msg));
			continue;
		}
		if((type==TYPE(RECORD_DEFINE))&&(subtype==SUBTYPE(RECORD_DEFINE,GOODS_INFO)))
		{
			ret=proc_record_goods_info(sub_proc,recv_msg);
		}
		else if((type==TYPE(ACTION_DEFINE))&&(subtype==SUBTYPE(ACTION_DEFINE,GOODS_FIND)))
		{
			ret=proc_action_goods_find(sub_proc,recv_msg);
		}
		else if((type==TYPE(RECORD_DEFINE))&&(subtype==SUBTYPE(RECORD_DEFINE,ORDER)))
		{
			ret=proc_record_order(sub_proc,recv_msg);
        }
		else if((type==TYPE(ACTION_DEFINE))&&(subtype==SUBTYPE(ACTION_DEFINE,ORDER_CONFIRM)))
		{
			ret=proc_action_confirm(sub_proc,recv_msg);
        }
	}
	return 0;
}

int proc_record_goods_info(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(RECORD_DEFINE,GOODS_INFO) * goods_info;

	void * new_msg;
	
	ret=message_get_record(recv_msg,&goods_info,0);
	if(ret<0)
		return ret;

// find the goods info , 
	DB_RECORD * db_record;

	db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),"id",goods_info->id);
	if(db_record==NULL)
	{
	    memdb_store(goods_info,TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),NULL);
        ex_module_sendmsg(sub_proc,recv_msg);
	}
	else
	{
        // get old goods num and add it to the goods info
        memdb_remove_record(db_record);
	    RECORD(RECORD_DEFINE,GOODS_INFO) * old_goods;
        old_goods = db_record->record;
        if(old_goods!=NULL)
		    goods_info->num += old_goods->num;
	    memdb_store(goods_info,TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),NULL);

        void * new_msg = message_create(TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),recv_msg);
        if(new_msg ==NULL)
            return  -EINVAL;
            
        message_add_record(new_msg,goods_info); 
        ex_module_sendmsg(sub_proc,new_msg);
	}
    void * type_msg;
    RECORD(MESSAGE,TYPES) types_pair;

    types_pair.type=TYPE(RECORD_DEFINE);
    types_pair.subtype=SUBTYPE(RECORD_DEFINE,GOODS_INFO);

    type_msg=message_create(TYPE_PAIR(MESSAGE,TYPES),NULL);

    message_add_record(type_msg,&types_pair);
    ex_module_sendmsg(sub_proc,type_msg);
	
	return ret;
}
int proc_action_goods_find(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(ACTION_DEFINE,GOODS_FIND) * goods_find;
	RECORD(RECORD_DEFINE,GOODS_INFO) * goods_info;

	void * new_msg;
	
	ret=message_get_record(recv_msg,(void **)&goods_find,0);
	if(ret<0)
		return ret;

// find the goods info , 
	DB_RECORD * db_record;

	db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),"id",goods_find->goods_id);
	if(db_record==NULL)
        return -EINVAL;   
    // get old goods num and add it to the goods info
    goods_info = db_record->record;
    if(goods_info==NULL)
        return -EINVAL;

    new_msg=message_create(TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),recv_msg);
    if(new_msg==NULL)
        return -EINVAL;
	message_add_record(new_msg,goods_info);
    ex_module_sendmsg(sub_proc,new_msg);
    return 0; 
}

char * Rand_id(int size)
{
    int i;
    if(size<=0)
        return NULL;
    unsigned char * temp = Talloc0(size);
    if(temp==NULL)
        return NULL;
    RAND_bytes(temp,size);
    temp[0]=temp[0]%9+'1';
    for(i=1;i<size;i++)
        temp[i]=temp[i]%10+'0';        
    return temp;
}

int proc_record_order(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(RECORD_DEFINE,ORDER) * order;
    DB_RECORD * db_record;
	void * new_msg;
	
	ret=message_get_record(recv_msg,&order,0);
	if(ret<0)
		return ret;

    // if order's id is empty, then apply an random id num

    if(order->order_id == NULL)
        order->order_id=Rand_id(id_size);
    else if(order->order_id[0]=='\0')
        order->order_id=Rand_id(id_size);

// find if there is an old order,if it exist,replace it 
    
	db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,ORDER),"order_id",order->order_id);
	if(db_record!=NULL)
	{
        memdb_remove_record(db_record);
	}
//  check if there has enough goods for order

    db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),"id",order->goods_id);
    if(db_record==NULL)
    {
        Memset(order->order_id,'0',id_size);
    }
    else
    {
        RECORD(RECORD_DEFINE,GOODS_INFO) * goods_info;
        goods_info=db_record->record;
        if(goods_info->num < order->num)
        {
            Memset(order->order_id,'0',id_size);
            order->order_id[1]='1';
        }
        else
        {
            order->cost = goods_info->cost * order->num;
            order->state=COMMIT;
    	    memdb_store(order,TYPE_PAIR(RECORD_DEFINE,ORDER),NULL);

            void * type_msg;
            RECORD(MESSAGE,TYPES) types_pair;

            types_pair.type=TYPE(RECORD_DEFINE);
            types_pair.subtype=SUBTYPE(RECORD_DEFINE,ORDER);

            type_msg=message_create(TYPE_PAIR(MESSAGE,TYPES),NULL);

            message_add_record(type_msg,&types_pair);
            ex_module_sendmsg(sub_proc,type_msg);
         }
    }
    new_msg=message_create(TYPE_PAIR(RECORD_DEFINE,ORDER),recv_msg);

    message_add_record(new_msg,order);
    ex_module_sendmsg(sub_proc,new_msg);
	
	return ret;
}

int proc_action_confirm(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(ACTION_DEFINE,ORDER_CONFIRM) * action_confirm;
	RECORD(RECORD_DEFINE,GOODS_INFO) * goods_info;
	RECORD(RECORD_DEFINE,ORDER) * order;
    DB_RECORD * db_record;
	void * new_msg;
	
	ret=message_get_record(recv_msg,&action_confirm,0);
	if(ret<0)
		return ret;

// find if there is an order 
    
	db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,ORDER),"order_id",action_confirm->order_id);
	if(db_record == NULL)
	{
        return -EINVAL;
	}
    order=db_record->record;

    if(order->state != action_confirm->state-1)
        return -EINVAL;
    memdb_remove_record(db_record);
    order->state=action_confirm->state;
    memdb_store(order,TYPE_PAIR(RECORD_DEFINE,ORDER),NULL);


    if(action_confirm->state == CONFIRMED)
    {
        db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),"id",order->goods_id);
        if(db_record==NULL)
        {
            return -EINVAL;
        }
        else
        {
            RECORD(RECORD_DEFINE,GOODS_INFO) * goods_info;
            goods_info=db_record->record;
            if(goods_info->num < order->num)
                return -EINVAL;
            goods_info->num-=order->num;
            memdb_remove_record(db_record);
            memdb_store(goods_info,TYPE_PAIR(RECORD_DEFINE,GOODS_INFO),NULL);
        }

        void * type_msg;
        RECORD(MESSAGE,TYPES) types_pair;

        types_pair.type=TYPE(RECORD_DEFINE);
        types_pair.subtype=SUBTYPE(RECORD_DEFINE,ORDER);

        type_msg=message_create(TYPE_PAIR(MESSAGE,TYPES),NULL);

        message_add_record(type_msg,&types_pair);
        types_pair.subtype=SUBTYPE(RECORD_DEFINE,GOODS_INFO);
        message_add_record(type_msg,&types_pair);
        ex_module_sendmsg(sub_proc,type_msg);
    }
    new_msg=message_create(TYPE_PAIR(RECORD_DEFINE,ORDER),recv_msg);

    message_add_record(new_msg,order);
    ex_module_sendmsg(sub_proc,new_msg);
	
	return ret;
}
/*
int proc_record_write(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(RECORD_DEFINE,RECORD) * record_data;
	RECORD(RECORD_DEFINE,WRITE) * write_data;
	RECORD(USER_DEFINE,RETURN) * return_info;
	RECORD(USER_DEFINE,SERVER_STATE) * user_state;

	void * new_msg;
	
	ret=message_get_record(recv_msg,&write_data,0);
	if(ret<0)
		return ret;

	return_info=Talloc0(sizeof(*return_info));
	if(return_info==NULL)
		return -ENOMEM;

// find the user state, 
	DB_RECORD * db_record;

//	find the record

	db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,RECORD),"record_no",write_data->record_no);
	if(db_record==NULL)
	{
		record_data=Talloc0(sizeof(*record_data));
		record_data->record_no = dup_str(write_data->record_no,0);
	}
	else
	{
		record_data=db_record->record;
	}


	void * record_template = memdb_get_template(TYPE_PAIR(RECORD_DEFINE,RECORD));
	if(record_template==NULL)
		return -EINVAL;
	
	ret = struct_write_elem_text(write_data->segment,record_data,write_data->text,record_template);
	if(ret<0)
		return -EINVAL;

	memdb_store(record_data,TYPE_PAIR(RECORD_DEFINE,RECORD),NULL);

	return_info->return_code=SUCCEED;
	return_info->return_info=dup_str("write data succeed!\n",0);

	// send a message store notice
    void * type_msg;
    RECORD(MESSAGE,TYPES) types_pair;

    types_pair.type=TYPE(RECORD_DEFINE);
    types_pair.subtype=SUBTYPE(RECORD_DEFINE,RECORD);

    type_msg=message_create(TYPE_PAIR(MESSAGE,TYPES),NULL);

    message_add_record(type_msg,&types_pair);
    ex_module_sendmsg(sub_proc,type_msg);
	

write_out:
	new_msg=message_create(TYPE_PAIR(USER_DEFINE,RETURN),recv_msg);	
	if(new_msg==NULL)
		return -EINVAL;
	ret=message_add_record(new_msg,return_info);
	if(ret<0)
		return ret;
	
	ret=ex_module_sendmsg(sub_proc,new_msg);
	return ret;
}

int proc_record_read(void * sub_proc,void * recv_msg)
{
	int ret;
	RECORD(RECORD_DEFINE,RECORD) * record_data;
	RECORD(RECORD_DEFINE,READ) * read_data;
	RECORD(USER_DEFINE,SERVER_STATE) * user_state;
	RECORD(USER_DEFINE,RETURN) * return_info;
	void * new_msg;
	
	ret=message_get_record(recv_msg,&read_data,0);
	if(ret<0)
		return ret;
// find the user state, 
	DB_RECORD * db_record;

	// find the record
	db_record=memdb_find_first(TYPE_PAIR(RECORD_DEFINE,RECORD),"record_no",read_data->record_no);
	if(db_record==NULL)
	{
		record_data=Talloc0(sizeof(*record_data));
		record_data->record_no = dup_str(read_data->record_no,0);
	}
	else
	{
		record_data=db_record->record;
	}


	new_msg=message_create(TYPE_PAIR(RECORD_DEFINE,RECORD),recv_msg);	
	if(new_msg==NULL)
		return -EINVAL;
	ret=message_add_record(new_msg,record_data);
	if(ret<0)
		return ret;
	
	ret=ex_module_sendmsg(sub_proc,new_msg);
	return ret;
}*/

